/* This source file is part of the Delectable Engine.
 * For the latest info, please visit http://delectable.googlecode.com/
 *
 * Copyright (c) 2009-2010 Ryan Chew
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file KeyboardManager.cpp
 * @brief Keyboard manager component.
 */

// Delectable Headers //
#include "dbl/Input/KeyboardManager.h"
#include "dbl/Core/GameWindow.h"

// Chewable Headers //
#include <cbl/Debug/Assert.h>
#include <cbl/Debug/Logging.h>
#include <cbl/Core/Game.h>

using namespace dbl;

KeyboardManager::KeyboardManager( cbl::Game & game )
: cbl::GameComponent( game )
, mWindow( NULL )
{
}

KeyboardManager::~KeyboardManager()
{
}


void KeyboardManager::Initialise( void )
{
	mWindow = this->Game.Services.Get< GameWindow >();
	CBL_ASSERT_TRUE( mWindow );
	
	GLOG( "Initialising keyboard manager." );

	mWindow->OnWindowKeyDown	+= *this;
	mWindow->OnWindowKeyUp		+= *this;
	mWindow->OnWindowKeyChar	+= *this;
	mWindow->OnWindowLostFocus	+= *this;
}

void KeyboardManager::Shutdown( void )
{
	if( !mWindow )
		return;

	GLOG( "Shutting down keyboard manager." );
	mWindow->OnWindowLostFocus	-= *this;
	mWindow->OnWindowKeyChar	-= *this;
	mWindow->OnWindowKeyUp		-= *this;
	mWindow->OnWindowKeyDown	-= *this;

	mWindow = NULL;
}

void KeyboardManager::Update( const cbl::GameTime & )
{
	for( cbl::Uint32 count = 0; count < Key::Count; ++count )
	{
		if( !mKeys[count] )
			continue;

		OnKeyDown( E::OnKeyDown::ArgType(
			Key::Code( count ),
			( mKeys[ Key::RShift ] || mKeys[ Key::LShift ] ? Key::Modifier::Shift : 0 ) |
			( mKeys[ Key::RAlt ] || mKeys[ Key::LAlt ] ? Key::Modifier::Alt : 0 ) |
			( mKeys[ Key::RCtrl ] || mKeys[ Key::LCtrl ] ? Key::Modifier::Ctrl : 0 )
			) );
	}
}

DEF_EVENT_HANDLER( KeyboardManager, E::OnWindowKeyDown )
{
	if( mKeys[ args.KeyCode ] )
		return;

	mKeys[ args.KeyCode ] = true;

	OnKeyClick( E::OnKeyClick::ArgType(
		args.KeyCode,
		( mKeys[ Key::RShift ] || mKeys[ Key::LShift ] ? Key::Modifier::Shift : 0 ) |
		( mKeys[ Key::RAlt ] || mKeys[ Key::LAlt ] ? Key::Modifier::Alt : 0 ) |
		( mKeys[ Key::RCtrl ] || mKeys[ Key::LCtrl ] ? Key::Modifier::Ctrl : 0 )
		) );
}

DEF_EVENT_HANDLER( KeyboardManager, E::OnWindowKeyUp )
{
	mKeys[ args.KeyCode ] = false;

	OnKeyUp( E::OnKeyUp::ArgType(
		args.KeyCode,
		( mKeys[ Key::RShift ] || mKeys[ Key::LShift ] ? Key::Modifier::Shift : 0 ) |
		( mKeys[ Key::RAlt ] || mKeys[ Key::LAlt ] ? Key::Modifier::Alt : 0 ) |
		( mKeys[ Key::RCtrl ] || mKeys[ Key::LCtrl ] ? Key::Modifier::Ctrl : 0 )
		) );
}

DEF_EVENT_HANDLER( KeyboardManager, E::OnWindowKeyChar )
{
	OnKeyChar( E::OnKeyChar::ArgType( args.Unicode ) );
}

DEF_EVENT_HANDLER_NA( KeyboardManager, E::OnWindowLostFocus )
{
	for( cbl::Uint32 count = 0; count < Key::Count; ++count )
	{
		if( !mKeys[ count ] )
			continue;

		mKeys[ count ] = false;
		OnKeyUp( E::OnKeyUp::ArgType(
			Key::Code( count ),
			( mKeys[ Key::RShift ] || mKeys[ Key::LShift ] ? Key::Modifier::Shift : 0 ) |
			( mKeys[ Key::RAlt ] || mKeys[ Key::LAlt ] ? Key::Modifier::Alt : 0 ) |
			( mKeys[ Key::RCtrl ] || mKeys[ Key::LCtrl ] ? Key::Modifier::Ctrl : 0 )
			) );
	}
}
